﻿using System;
using System.Diagnostics;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows.Input;
using System.Threading;
using EnvDTE;

namespace CodeJumper
{
    /// <summary>
    /// Interaction logic for ElementView.xaml
    /// </summary>
    public partial class ElementView : UserControl
    {
        private CodeJumper thisParent;
        private double savedVerticalOffset = 0.0;
        public ApplicationConfiguration AppConfig { get; set; }
        public ElementView(ApplicationConfiguration AppConfig)
        {
            DataContext = this;

            this.AppConfig = AppConfig;

            this.FontFamily = new System.Windows.Media.FontFamily("Ravie");
            InitializeComponent();
        }

        public void SetParent(CodeJumper parent)
        {
            thisParent = parent;
        }

        public void InitiateUpdate()
        {
            //Trace.WriteLine(AppConfig.Dte.ActiveDocument.Name);

            if (AppConfig.DocumentParser.HasAllInformation == false)
            {
                Trace.WriteLine("No metadata to start analysis.");
                return;
            }

            AppConfig.DocumentParser.ParserComplete += parser_ParserComplete;
            AppConfig.DocumentParser.ParserProgress += DocumentParser_ParserProgress;
            System.Threading.Thread thread = new System.Threading.Thread(new ThreadStart(() =>
                {
                    bool success = AppConfig.DocumentParser.ParseDocument();

                    if (!success)
                    {
                        AppConfig.DispatcherSemaphore.Release();
                        AppConfig.DocumentParser.ParserComplete -= parser_ParserComplete;
                    }


                }));
            thread.SetApartmentState(ApartmentState.MTA);
            thread.IsBackground = true;
            thread.DisableComObjectEagerCleanup();
            thread.Name = "Code Jumper Document Parser";
            thread.Priority = ThreadPriority.Lowest;
            thread.Start();
        }

        void DocumentParser_ParserProgress(DocumentParser sender)
        {
            sender.RootElement.Draw();
            sender.RootElement.UpdateAll();
            stackPanel2.Children.Clear();
            stackPanel2.Children.Add(AppConfig.DocumentParser.RootElement.GetVisualElement());

            this.UpdateLayout();
            this.InvalidateMeasure();
            this.InvalidateVisual();

          //  scrollViewer1.ScrollToVerticalOffset(savedVerticalOffset);

            
        }

        void parser_ParserComplete(DocumentParser sender)
        {
            AppConfig.DocumentParser.ParserComplete -= parser_ParserComplete;

            sender.RootElement.Draw();
            sender.RootElement.UpdateAll();
            stackPanel2.Children.Clear();
            stackPanel2.Children.Add(AppConfig.DocumentParser.RootElement.GetVisualElement());

            this.UpdateLayout();
            this.InvalidateMeasure();
            this.InvalidateVisual();

            scrollViewer1.ScrollToVerticalOffset(savedVerticalOffset);


            int semcnt = AppConfig.DispatcherSemaphore.Release();
            Trace.WriteLine(string.Format("FP Semaphore released. {0}", semcnt));

        }



        public void DeleteElement(CodeElement element)
        {
            bool result = AppConfig.DocumentParser.DeleteElement(element);

            if (result == false)
            {
                Trace.WriteLine("DeleteElement aggregate could not be determined. Commencing full update.");
                InitiateUpdate();
                return;
            }

            AppConfig.DocumentParser.RootElement.Draw();
            AppConfig.DocumentParser.RootElement.UpdateAll();
            stackPanel2.Children.Clear();
            stackPanel2.Children.Add(AppConfig.DocumentParser.RootElement.GetVisualElement());

            this.UpdateLayout();
            this.InvalidateMeasure();
            this.InvalidateVisual();

            scrollViewer1.ScrollToVerticalOffset(savedVerticalOffset);

            int semcnt = AppConfig.DispatcherSemaphore.Release();
            Trace.WriteLine(string.Format("DE Semaphore released. {0}", semcnt));

        }

        public void ChangeElement(CodeElement element)
        {
            var aggregate = AppConfig.DocumentParser.ChangeElement(element);

            if (aggregate == null)
            {
                Trace.WriteLine("ChangeElement aggregate could not be determined. Commencing full update.");
                InitiateUpdate();
                return;
            }

            Trace.WriteLine(string.Format("Changed aggregate {0}", aggregate.FullName));

            (aggregate.GetVisualElement() as ElementStackPanel).Children.Clear();
            aggregate.DrawChildren();
            aggregate.UpdateChildren();
            //stackPanel2.Children.Clear();
            //stackPanel2.Children.Add(AppConfig.DocumentParser.RootElement.GetVisualElement());

            //this.UpdateLayout();
            //this.InvalidateMeasure();
            //this.InvalidateVisual();

            scrollViewer1.ScrollToVerticalOffset(savedVerticalOffset);


            int semcnt = AppConfig.DispatcherSemaphore.Release();
            Trace.WriteLine(string.Format("CE Semaphore released. {0}", semcnt));
        }


        private void GridSplitter_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            Trace.WriteLine(string.Format("delta {0}", e.HorizontalChange));
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            OptionsWindow opt = new OptionsWindow(AppConfig);

            opt.ShowDialog();
        }

        private void MenuItem_Click_1(object sender, RoutedEventArgs e)
        {
            InitiateUpdate();
        }

        public void ScrollByEvent(MouseWheelEventArgs e)
        {
            int num = 0;
            if (e.Delta < 0)
            {
                num = 50;
            }
            else if (e.Delta > 0)
            {
                num = -50;
            }
            if (num != 0)
            {
                savedVerticalOffset = scrollViewer1.VerticalOffset + num;
               
                scrollViewer1.ScrollToVerticalOffset(scrollViewer1.VerticalOffset + num);
            }

        }

        private void splitter1_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
        {
            ScrollByEvent(e);
        }

        private void CollapseAll(object sender, RoutedEventArgs e)
        {
            if (AppConfig.DocumentParser == null)
                return;
            if (AppConfig.DocumentParser.RootElement == null)
                return;
            foreach (var child in AppConfig.DocumentParser.RootElement.Children)
            {
                if (child.IsStackableElement)
                {
                    (child.GetVisualElement() as ElementStackPanel).Collapse();
                }
            }
        }

        private void ExpandAll(object sender, RoutedEventArgs e)
        {
            if (AppConfig.DocumentParser == null)
                return;
            if (AppConfig.DocumentParser.RootElement == null)
                return;

            foreach (var child in AppConfig.DocumentParser.RootElement.Children)
            {
                if (child.IsStackableElement)
                {
                    (child.GetVisualElement() as ElementStackPanel).Expand();
                }
            }
        }

        private void scrollViewer1_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            savedVerticalOffset = e.VerticalOffset;
        }

    }
}
